#include "eqfreqdiagram.h"
#include "dm/dmdef.h"

#include <algorithm>

// pen width
constexpr int PEN_WIDTH = 2;
// 标签宽
constexpr double LABEL_W = 60;
// 标签高
constexpr double LABEL_H = 30;
// 偏移量
constexpr double OFFSET_L = LABEL_W + 5;
constexpr double OFFSET_R = 30;
constexpr double OFFSET_T = 40;
constexpr double OFFSET_B = 40;


EqFreqDiagram::EqFreqDiagram(QWidget *parent)
    : QWidget{parent}
    , m_selectedIndex{-1}
{
    setMouseTracking(true);
    setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    setMinimumSize(1600, 500);

}

EqFreqDiagram::~EqFreqDiagram()
{
    qDeleteAll(m_rects);
    m_rects.clear();
}

void EqFreqDiagram::setEqList(const QList<EQ> &list)
{
    qDeleteAll(m_rects);
    m_rects.clear();
    for (auto i = 0; i < list.size(); ++i) {
        auto rectangle = new Rectangle(list.at(i), this);
        rectangle->number = i;
        m_rects.push_back(rectangle);
        connect(rectangle, &Rectangle::stateChanged, this, &EqFreqDiagram::stateChanged);
    }
}

void EqFreqDiagram::stateChanged(const int &number)
{
    auto &rectangle = m_rects[number];
    rectangle->move(toPoint(m_cRect, rectangle->eq().freq, rectangle->eq().gain));
    m_selectedIndex = number;
    update();
}

void EqFreqDiagram::setArg(const int &index, const EQ &eq)
{
    if (index > -1 && index < m_rects.size()) {
        auto &rectangle = m_rects[index];
        rectangle->setEq(eq);
        rectangle->move(toPoint(m_cRect, rectangle->eq().freq, rectangle->eq().gain));
        m_selectedIndex = index;
        update();
    }
}

void EqFreqDiagram::paintEvent(QPaintEvent *event)
{
    Q_UNUSED(event);
    QPainter painter(this);
    painter.setRenderHint(QPainter::Antialiasing, true);
    painter.setRenderHint(QPainter::SmoothPixmapTransform, true);

    auto pen = painter.pen();
    pen.setWidth(PEN_WIDTH);
    // painter.setBrush(Qt::black);
    painter.setPen(pen);

    const double w = width() - PEN_WIDTH;
    const double h = height() - PEN_WIDTH;

    painter.drawRect(PEN_WIDTH / 2, PEN_WIDTH / 2, w, h);


    // 坐标系实际大小
    const double aw = w - OFFSET_L - OFFSET_R;
    const double ah = h - OFFSET_T - OFFSET_B;

    m_cRect = QRectF(OFFSET_L, OFFSET_T, aw, ah);

    const auto oy = m_cRect.bottomLeft().y();
    const auto ox = m_cRect.bottomLeft().x();

    // 坐标系框
    pen.setWidth(1);
    pen.setColor(Qt::gray);
    painter.setPen(pen);
    // 网格线
    // y轴
    for (int gain = EQ_GAIN_MIN; gain <= EQ_GAIN_MAX; gain += EQ_GAIN_LABEL_STEP / 2) {
        auto p1 = toPoint(m_cRect, EQ_FREQUENCY_MIN, gain);
        auto p2 = toPoint(m_cRect, EQ_FREQUENCY_MAX, gain);
        painter.drawLine(p1, p2);
        if (0 == gain % EQ_GAIN_LABEL_STEP) {
            auto str = QString::number(gain);
            if (0 == gain) {
                str += LABEL_DECIBEL_UINT;
            }
            painter.drawText(QRectF(ox - OFFSET_L, p1.y() - LABEL_H / 2, LABEL_W, LABEL_H), Qt::AlignVCenter | Qt::AlignRight, str);
        }
    }
    // x轴
    for (size_t i = 0; i < EQ_FREQUENCY_AUX.size(); ++i) {
        auto aux = EQ_FREQUENCY_AUX.at(i);
        auto p1 = toPoint(m_cRect, EQ_FREQUENCY_AUX.at(i), EQ_GAIN_MAX);
        auto p2 = toPoint(m_cRect, EQ_FREQUENCY_AUX.at(i), EQ_GAIN_MIN);
        painter.drawLine(p1, p2);
        if (std::find(EQ_FREQUENCY_LABEL.begin(), EQ_FREQUENCY_LABEL.end(), aux) != EQ_FREQUENCY_LABEL.end()) {
            QString str;
            if (aux < 1000) {
                str = QString::number(aux);
            }
            else {
                str = QString::number(aux / 1000) + "K";
            }
            painter.drawText(QRectF(p1.x() - LABEL_W / 2, oy, LABEL_W, LABEL_H), Qt::AlignCenter, str);
        }
    }

    // 阴影
    if (m_selectedIndex > -1) {
        std::vector<QPointF> cps(EQ_FREQUENCY_COUNT + 2);
        if (cps.empty()) {
            return;
        }
        // 阴影部分起始和结束点为0dB线两端
        cps.front() = QPointF(m_cRect.topLeft().x(), m_cRect.y() + ah * EQ_GAIN_MAX / EQ_GAIN_LENGTH);
        for (size_t i = 1; i < cps.size() - 1; ++i) {
            cps[i] = toPoint(m_cRect, EQ_FREQUENCY.at(i - 1), m_rects.at(m_selectedIndex)->parr().at(i - 1));
        }
        cps.back() = QPointF(m_cRect.topRight().x(), m_cRect.y() + ah * EQ_GAIN_MAX / EQ_GAIN_LENGTH);
        pen.setWidth(1);
        pen.setColor(QColor(176, 224, 230, 128));
        painter.setPen(pen);
        painter.setBrush(QColor(176, 224, 230, 128));
        painter.drawPath(getPath(cps));
    }

    // 频率曲线
    pen.setWidth(3);
    pen.setColor(QColor(30, 144, 255)); // 蓝色
    painter.setPen(pen);
    painter.setBrush(Qt::NoBrush);

    std::vector<QPointF> tps(EQ_FREQUENCY.size());
    for (size_t i = 0; i < EQ_FREQUENCY.size(); ++i) {
        double tgain = 0;
        for (auto j = 0; j < m_rects.size(); ++j) {
            tgain += m_rects.at(j)->parr().at(i);
        }
        tps[i] = toPoint(m_cRect, EQ_FREQUENCY.at(i), tgain);
    }

    if (tps.empty()) {
        return;
    }
    painter.drawPath(getPath(tps));

    // 拖拽控件
    pen.setWidth(PEN_WIDTH);
    pen.setColor(Qt::black);
    painter.setPen(pen);
    painter.setBrush(Qt::NoBrush);

    for (auto i = 0; i < m_rects.size(); ++i) {
        auto &rectangle = m_rects.at(i);
        rectangle->move(toPoint(m_cRect, m_rects.at(i)->eq().freq, m_rects.at(i)->eq().gain));
        painter.drawRoundedRect(rectangle->rect, 30, 30, Qt::RelativeSize);
        painter.drawText(rectangle->rect, Qt::AlignCenter, QString::number(rectangle->number + 1));
        if (m_selectedIndex == i) {
            painter.drawRect(rectangle->lRect);
            painter.drawRect(rectangle->rRect);
        }
    }
}

void EqFreqDiagram::mousePressEvent(QMouseEvent *event)
{
    if (event->button() == Qt::LeftButton) {
        // 检查鼠标是否点击在某个矩形内
        for (auto i = 0; i < m_rects.size(); ++i) {
            if (m_rects[i]->contains(event->pos())) {
                m_selectedIndex = i;
                update();
                return;
            }

        }
        // 如果点击在矩形外，取消选中
        m_selectedIndex = -1;
        update();
    }

    QWidget::mousePressEvent(event);
}

void EqFreqDiagram::mouseMoveEvent(QMouseEvent *event)
{
    setCursor(Qt::ArrowCursor);
    for (auto i = 0; i < m_rects.size(); ++i) {
        if (m_rects[i]->rect.contains(event->pos()) || m_rects[i]->lRect.contains(event->pos()) || m_rects[i]->rRect.contains(event->pos())) {
            setCursor(Qt::PointingHandCursor);
            break;
        }
    }
    // 如果有选中的矩形并且正在拖拽
    if (m_selectedIndex != -1) {
        if (m_rects[m_selectedIndex]->isDragging) {
            auto arg = m_rects[m_selectedIndex]->eq();
            // 计算freq 和 gain 并发送
            auto pair = toFreqAndGain(event->pos());
            arg.freq = pair.first;
            arg.gain = pair.second;
            emit argChanged(m_selectedIndex, arg);
        }
        else if (m_rects[m_selectedIndex]->isLDragging) {
            auto arg = m_rects[m_selectedIndex]->eq();
            int bw = m_rects[m_selectedIndex]->rect.center().x() - EQ_BW_DEFAULT - event->pos().x();
            arg.bw = std::clamp(bw, EQ_BW_MIN, EQ_BW_MAX);
            emit argChanged(m_selectedIndex, arg);
        }
        else if (m_rects[m_selectedIndex]->isRDragging) {
            auto arg = m_rects[m_selectedIndex]->eq();
            int bw = event->pos().x() - m_rects[m_selectedIndex]->rect.center().x() - EQ_BW_DEFAULT;
            arg.bw = std::clamp(bw, EQ_BW_MIN, EQ_BW_MAX);
            emit argChanged(m_selectedIndex, arg);
        }

    }

    QWidget::mouseMoveEvent(event);
}

void EqFreqDiagram::mouseReleaseEvent(QMouseEvent *event)
{
    // 结束拖拽
    if (m_selectedIndex != -1 && event->button() == Qt::LeftButton) {
        m_rects[m_selectedIndex]->dragEnd();
    }

    QWidget::mouseReleaseEvent(event);
}

QPainterPath EqFreqDiagram::getPath(const std::vector<QPointF> &vect) const
{
    QPainterPath tpath;
    if (vect.empty()) {
        return tpath;
    }

    // 单个点：画标记
    if (vect.size() == 1) {
        tpath.addEllipse(vect.at(0), 2, 2);
        return tpath;
    }

    tpath.moveTo(vect.at(0));

    // 两个点：直接直线连接
    if (vect.size() == 2) {
        tpath.lineTo(vect.at(1));
        return tpath;
    }

    // 多个点：三次贝塞尔，控制点沿线段方向
    for (size_t i = 0; i < vect.size() - 1; ++i) {
        QPointF curr = vect.at(i);
        QPointF next = vect.at(i + 1);
        QPointF dir = next - curr; // 线段的方向向量

        // 控制点沿线段延长线（scale调整弯曲程度，0.2为推荐值，可微调）
        const qreal scale = 0.25;
        QPointF ctrl1 = curr + dir * scale;   // 第一个控制点（沿curr→next方向）
        QPointF ctrl2 = next - dir * scale;   // 第二个控制点（沿next→curr方向）

        tpath.cubicTo(ctrl1, ctrl2, next);
    }

    return tpath;
}

QPointF EqFreqDiagram::toPoint(const QRectF &rect, const double &freq, const double &gain) const
{
    return QPointF(rect.x() + rect.width() * Filter::freqToWidth(freq), rect.y() + rect.height() * Filter::gainToHeight(gain));
}

std::pair<double, double> EqFreqDiagram::toFreqAndGain(const QPointF &point) const
{
    return std::make_pair(Filter::widthToFreq(m_cRect.width(), point.x() - m_cRect.x()),
                          Filter::heightToGain(m_cRect.height(), point.y() - m_cRect.y()));
}



